/*
 * Copyright 2007-2008 Andrew O'Malley
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package ws.quokka.plugin.remotecopy;

import org.apache.tools.ant.BuildException;

import ws.quokka.core.bootstrap_util.IOUtils;
import ws.quokka.core.metadata.Metadata;
import ws.quokka.core.metadata.MetadataAware;
import ws.quokka.core.plugin_spi.support.AbstractPlugin;
import ws.quokka.core.plugin_spi.support.TypedProperties;
import ws.quokka.core.repo_spi.RepoArtifact;
import ws.quokka.core.repo_spi.RepoArtifactId;
import ws.quokka.core.repo_spi.RepoType;
import ws.quokka.core.repo_spi.RepoXmlConverter;
import ws.quokka.core.repo_spi.Repository;
import ws.quokka.core.repo_spi.RepositoryAware;
import ws.quokka.core.repo_spi.RepositoryFactory;
import ws.quokka.core.repo_spi.RepositoryFactoryAware;

import ws.quokka.plugin.remotecopy.webdav.WebDavRemoteCopy;

import java.io.File;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


/**
 *
 */
public class RemoteCopyPlugin extends AbstractPlugin implements MetadataAware, RepositoryFactoryAware, RepositoryAware {
    //~ Instance fields ------------------------------------------------------------------------------------------------

    private Metadata metadata;
    private RepositoryFactory repositoryFactory;
    private Repository repository;

    //~ Methods --------------------------------------------------------------------------------------------------------

    public void setMetadata(Metadata metadata) {
        this.metadata = metadata;
    }

    public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
        this.repositoryFactory = repositoryFactory;
    }

    public void setRepository(Repository repository) {
        this.repository = repository;
    }

    public void copyArtifacts() {
        String pathId = properties().getString("path", null);
        List artifacts = (pathId == null) ? getExportedArtifacts() : metadata.getProjectPath(pathId);

        String protocol = properties().getString("protocol");
        String mount = properties().getString("mount", null);

        RemoteCopy snapshots = null;
        RemoteCopy releases = null;

        try {
            for (Iterator i = artifacts.iterator(); i.hasNext();) {
                RepoArtifact artifact = (RepoArtifact)i.next();

                RemoteCopy remoteCopy;

                if (artifact.getId().getVersion().isSnapShot()) {
                    if (snapshots == null) {
                        snapshots = createRemoteCopy(protocol, properties().sub("snapshots."));
                    }

                    remoteCopy = snapshots;
                } else {
                    if (releases == null) {
                        releases = createRemoteCopy(protocol, properties().sub("releases."));
                    }

                    remoteCopy = releases;
                }

                // Copy artifact
                RepoType type = repositoryFactory.getType(artifact.getId().getType());
                String extension = type.getId() + "." + type.getExtension();
                remoteCopy.copy(artifact.getLocalCopy(), getPath(getRepositoryPath(artifact.getId(), extension), mount));

                // Copy repository.xml
                File temp = new IOUtils().createTempFile("quokka", "_repository.xml");

                try {
                    RepoXmlConverter.toXml(artifact, temp);
                    extension = type.getId() + "_repository.xml";
                    remoteCopy.copy(temp, getPath(getRepositoryPath(artifact.getId(), extension), mount));
                } finally {
                    temp.delete();
                }
            }
        } finally {
            if (snapshots != null) {
                snapshots.close();
            }

            if (releases != null) {
                releases.close();
            }
        }
    }

    private List getExportedArtifacts() {
        List artifacts = new ArrayList();
        List exported = metadata.getExportedArtifacts();

        for (Iterator i = exported.iterator(); i.hasNext();) {
            RepoArtifact artifact = (RepoArtifact)i.next();
            artifacts.add(repository.resolve(artifact.getId()));
        }

        return artifacts;
    }

    public void copy() {
        String protocol = properties().getString("protocol");
        RemoteCopy remoteCopy = createRemoteCopy(protocol, properties());

        try {
            String to = properties().getString("to");
            to = to.startsWith("/") ? to : ("/" + to);
            remoteCopy.copy(properties().getFile("file"), to);
        } finally {
            remoteCopy.close();
        }
    }

    /**
     * Turns a repository absolute path into remote server relative path
     */
    private String getPath(String absolutePath, String mount) {
        if (mount != null) {
            return absolutePath.substring(normalise(mount).length() - 1);
        }

        return absolutePath;
    }

    public static String normalise(String path) {
        path = path.startsWith("/") ? path : ("/" + path);
        path = path.endsWith("/") ? path : (path + "/");

        return path;
    }

    protected String getRepositoryPath(RepoArtifactId id, String extension) {
        return "/" + id.getGroup().replace('.', '/') + "/" + id.getVersion().toString() + "/" + id.getName() + "_"
        + extension;
    }

    private RemoteCopy createRemoteCopy(String protocol, TypedProperties properties) {
        if (protocol.equals("webdav")) {
            return new WebDavRemoteCopy(properties, log());
        }

        throw new BuildException("Unknown protocol: " + protocol);
    }
}
